import * as PIXI from 'pixi.js';
import { BaseNode } from "../nodes/com/BaseNode"
import { MainUi } from '../ui/MainUi'
import { NodeUtils } from './NodeUtils';
import { NodesSelector } from '../ui/NodesSelector';
import { ImportNode } from '../nodes/ImportNode';
import { SgScript } from './SgScript';
import { SgsEditor } from '../../uitls/sg-editor';
import { EditorOutputEvent } from '../../com/editor-struct';
export class DataBus {
    private static _data: any = {}
    public static nodes: BaseNode[] = []
    public static ui: MainUi
    public static app: PIXI.Application
    public static nodesBox: PIXI.Container
    private static _input?: HTMLTextAreaElement
    private static _inputBox: HTMLDivElement
    public static compilerReady = false
    public static selectedNode?: BaseNode
    private static _nodesSelector: NodesSelector

    public static set(key: string, value: any) {
        this._data[key] = value
    }
    public static get<T>(key: string) {
        return this._data[key] as (T | undefined)
    }
    public static remove(key: string) {
        delete this._data[key]
    }
    public static clear() {
        this._data = {}
    }

    public static get allNodes() {
        const imports: BaseNode[] = []
        const importNodes = DataBus.nodes.filter(n => n.type === 'Import') as ImportNode[]
        const baseNodes = DataBus.nodes.filter(n => n.type !== 'Import')
        importNodes.forEach(n => {
            const ns = n.nodes.filter(n => n.type !== 'main')
            imports.push(...ns)
        })
        return imports.concat(baseNodes)
    }

    public static get nodesSelector() {
        if (!this._nodesSelector) {
            this._nodesSelector = new NodesSelector()
            this.ui.view.addChild(this._nodesSelector.view)
        }
        return this._nodesSelector
    }

    public static activeNode(id: string) {
        const node = this.nodes.find(node => node.id === id)
        if (node) {
            node.setNodeActive()
        }
    }

    public static resetNodeActive() {
        for (const node of this.nodes) {
            node.setNodeUnActive()
        }
    }

    public static get input() {
        if (!DataBus._input) {
            DataBus._inputBox = document.createElement('div')
            DataBus._input = document.createElement('textarea')
            DataBus._inputBox.className = 'sgs-input'
            DataBus._inputBox.appendChild(DataBus._input)
            document.body.appendChild(DataBus._inputBox)
        }
        return DataBus._input
    }

    public static get inputBox() {
        return DataBus._inputBox
    }

    public static removeNodeAndChildren(node: BaseNode) {
        const outputs = [...node.outputs]
        DataBus.nodes.splice(DataBus.nodes.indexOf(node), 1)
        node.view.destroy()
        for (const output of outputs) {
            const id = output.socket?.connection?.node

            if (id) {
                const child = DataBus.nodes.find(n => n.id === id)
                if (child) {
                    DataBus.removeNodeAndChildren(child)
                }
            }
        }
    }

    public static async copyNodeAndChildren(node: BaseNode, first = true, ext?: string) {
        const temp = await NodeUtils.decode(NodeUtils.encode([node]))
        if (!temp || temp.length === 0) {
            return
        }
        const tempNode = temp[0]
        let nameExt = ext
        if (ext == undefined) {
            const nodes = DataBus.nodes.filter(n => n.titleContent.includes(tempNode.titleContent.split('_')[0]))
            const max = nodes.length
            nameExt = `_copy_${max}`
        }
        tempNode.setTitle(tempNode.titleContent.replace(/_copy_[0-9]+/, '') + nameExt)
        tempNode.id += nameExt
        const rect = tempNode.view.getBounds()
        tempNode.y += rect.height / 2
        DataBus.nodesBox.addChild(tempNode.view)
        DataBus.nodes.push(tempNode)
        if (first) {
            tempNode.clearInputs()
            tempNode.refresh()

        } else {
            for (const input of tempNode.inputs) {
                const id = input.socket?.connection?.node
                if (id && input.socket && input.socket.connection) {
                    input.socket.connection.node += nameExt
                }
            }
        }

        for (const output of tempNode.outputs) {
            const id = output.socket?.connection?.node
            if (id && output.socket && output.socket.connection) {
                output.socket.connection.node += nameExt

                const child = DataBus.nodes.find(n => n.id === id)
                if (child) {
                    DataBus.copyNodeAndChildren(child, false, nameExt)
                }
            }
        }
    }

    static getReferenceNode() {
        const nodes = DataBus.nodes.filter(node => {
            return node.canReference
        })
        return nodes.map(node => {
            return node.id
        })
    }

    static updateNode() {
        const json = SgScript.encode({
            x: DataBus.nodesBox.x,
            y: DataBus.nodesBox.y,
            scale: DataBus.nodesBox.scale.x
        }, DataBus.nodes)
        SgsEditor.callEnvMethod(EditorOutputEvent.UPDATE_FILE, json)
    }
}